/**
 * 法语句子相似度比对工具
 * 用于比较两段法语文本的相似度，返回0-100之间的得分
 */
export default class FrenchSentenceComparer {
  constructor(options = {}) {
    // 默认配置
    this.config = {
      removeAccents: options.removeAccents !== undefined ? options.removeAccents : true,
      ignoreCase: options.ignoreCase !== undefined ? options.ignoreCase : true,
      removePunctuation: options.removePunctuation !== undefined ? options.removePunctuation : true,
      // 相似度评分权重配置
      weights: {
        charSimilarity: options.weights?.charSimilarity || 0.5,
        wordSimilarity: options.weights?.wordSimilarity || 0.4,
        lengthSimilarity: options.weights?.lengthSimilarity || 0.1
      }
    };
  }

  /**
   * 标准化法语文本
   * @param {string} text - 要标准化的法语文本
   * @returns {string} 标准化后的文本
   */
  normalizeText(text) {
    if (!text) return '';
    
    let result = text;
    
    // 转换为小写
    if (this.config.ignoreCase) {
      result = result.toLowerCase();
    }
    
    // 移除标点符号
    if (this.config.removePunctuation) {
      // 保留连字符和省音符号，因为在法语中有实际意义
      result = result.replace(/[^\w\s'-]/g, '');
    }
    
    // 移除或规范化变音符号
    if (this.config.removeAccents) {
      // 规范化变音符号
      result = result.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
    }
    
    // 处理多余空格
    result = result.replace(/\s+/g, ' ').trim();
    
    return result;
  }

  /**
   * 计算字符相似度
   * @param {string} str1 - 第一个字符串
   * @param {string} str2 - 第二个字符串
   * @returns {number} 相似度得分 (0-1)
   */
  calculateCharSimilarity(str1, str2) {
    if (!str1 && !str2) return 1;
    if (!str1 || !str2) return 0;
    
    // 计算Damerau-Levenshtein距离（考虑插入、删除、替换和相邻字符交换）
    const distance = this.damerauLevenshteinDistance(str1, str2);
    const maxLength = Math.max(str1.length, str2.length);
    
    return (maxLength - distance) / maxLength;
  }

  /**
   * 计算Damerau-Levenshtein距离
   * @param {string} str1 - 第一个字符串
   * @param {string} str2 - 第二个字符串
   * @returns {number} 编辑距离
   */
  damerauLevenshteinDistance(str1, str2) {
    const m = str1.length;
    const n = str2.length;
    
    if (m === 0) return n;
    if (n === 0) return m;
    
    // 创建距离矩阵
    const d = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
    
    // 初始化矩阵
    for (let i = 0; i <= m; i++) {
      d[i][0] = i;
    }
    for (let j = 0; j <= n; j++) {
      d[0][j] = j;
    }
    
    // 填充矩阵
    for (let i = 1; i <= m; i++) {
      for (let j = 1; j <= n; j++) {
        const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
        
        d[i][j] = Math.min(
          d[i - 1][j] + 1,      // 删除
          d[i][j - 1] + 1,      // 插入
          d[i - 1][j - 1] + cost // 替换
        );
        
        // 检查相邻字符交换
        if (i > 1 && j > 1 && str1[i - 1] === str2[j - 2] && str1[i - 2] === str2[j - 1]) {
          d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost);
        }
      }
    }
    
    return d[m][n];
  }

  /**
   * 计算词相似度
   * @param {string} text1 - 第一个文本
   * @param {string} text2 - 第二个文本
   * @returns {number} 词相似度得分 (0-1)
   */
  calculateWordSimilarity(text1, text2) {
    const words1 = text1.split(' ');
    const words2 = text2.split(' ');
    
    if (words1.length === 0 && words2.length === 0) return 1;
    if (words1.length === 0 || words2.length === 0) return 0;
    
    // 创建词频映射
    const freq1 = this.getWordFrequency(words1);
    const freq2 = this.getWordFrequency(words2);
    
    // 计算交集词的权重和
    let intersectionWeight = 0;
    for (const word in freq1) {
      if (freq2[word]) {
        // 交集词的权重为两个频率的最小值
        intersectionWeight += Math.min(freq1[word], freq2[word]);
      }
    }
    
    // 计算并集词的权重和
    const unionWeight = Object.values(freq1).reduce((a, b) => a + b, 0) +
                        Object.values(freq2).reduce((a, b) => a + b, 0) -
                        intersectionWeight;
    
    // 基于词频的Jaccard相似度
    return unionWeight > 0 ? intersectionWeight / unionWeight : 1;
  }

  /**
   * 获取词频映射
   * @param {Array} words - 词数组
   * @returns {Object} 词频映射
   */
  getWordFrequency(words) {
    const freq = {};
    words.forEach(word => {
      freq[word] = (freq[word] || 0) + 1;
    });
    return freq;
  }

  /**
   * 计算文本长度相似度
   * @param {string} text1 - 第一个文本
   * @param {string} text2 - 第二个文本
   * @returns {number} 长度相似度得分 (0-1)
   */
  calculateLengthSimilarity(text1, text2) {
    const len1 = text1.length;
    const len2 = text2.length;
    
    if (len1 === 0 && len2 === 0) return 1;
    if (len1 === 0 || len2 === 0) return 0;
    
    // 基于长度差异的相似度计算，使用更平缓的衰减函数
    const lengthRatio = Math.min(len1, len2) / Math.max(len1, len2);
    return Math.pow(lengthRatio, 0.5); // 开平方使差异影响更平缓
  }

  /**
   * 比较两段法语句子的相似度
   * @param {string} sentence1 - 第一段法语句子
   * @param {string} sentence2 - 第二段法语句子
   * @returns {number} 相似度得分 (0-100)
   */
  compare(sentence1, sentence2) {
    // 特殊情况处理
    if (sentence1 === sentence2) {
      return 100;
    }
    
    // 标准化文本
    const normalized1 = this.normalizeText(sentence1);
    const normalized2 = this.normalizeText(sentence2);
    
    // 如果标准化后完全相同，直接返回100
    if (normalized1 === normalized2) {
      return 100;
    }
    
    // 如果标准化后有一个为空，另一个不为空，返回0
    if ((!normalized1 || !normalized2) && (normalized1 || normalized2)) {
      return 0;
    }
    
    // 计算各项相似度
    const charSim = this.calculateCharSimilarity(normalized1, normalized2);
    const wordSim = this.calculateWordSimilarity(normalized1, normalized2);
    const lenSim = this.calculateLengthSimilarity(normalized1, normalized2);
    
    // 加权平均计算最终相似度
    const finalScore = (
      charSim * this.config.weights.charSimilarity +
      wordSim * this.config.weights.wordSimilarity +
      lenSim * this.config.weights.lengthSimilarity
    ) * 100;
    
    // 返回保留两位小数的得分
    return Math.round(finalScore * 100) / 100;
  }

  /**
   * 获取相似度比较的详细分析
   * @param {string} sentence1 - 第一段法语句子
   * @param {string} sentence2 - 第二段法语句子
   * @returns {Object} 包含详细相似度分析的对象
   */
  getDetailedComparison(sentence1, sentence2) {
    const normalized1 = this.normalizeText(sentence1);
    const normalized2 = this.normalizeText(sentence2);
    
    const charSim = this.calculateCharSimilarity(normalized1, normalized2);
    const wordSim = this.calculateWordSimilarity(normalized1, normalized2);
    const lenSim = this.calculateLengthSimilarity(normalized1, normalized2);
    
    const finalScore = (
      charSim * this.config.weights.charSimilarity +
      wordSim * this.config.weights.wordSimilarity +
      lenSim * this.config.weights.lengthSimilarity
    ) * 100;
    
    return {
      originalTexts: {
        sentence1,
        sentence2
      },
      normalizedTexts: {
        normalized1,
        normalized2
      },
      similarityScores: {
        character: Math.round(charSim * 10000) / 100,
        word: Math.round(wordSim * 10000) / 100,
        length: Math.round(lenSim * 10000) / 100,
        final: Math.round(finalScore * 100) / 100
      },
      config: this.config
    };
  }
}    